﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using CalcSharp.Core;
using CalcSharp.Core.Containers;

namespace CalcSharp
{
    public class FunctionLoader
    {
        private Dictionary<string, int> Functions;
        
        public FunctionLoader()
        {
            this.Functions = new Dictionary<string, int>();

            Type Math = Type.GetType("CalcSharp.MathFuncts");
            MemberInfo[] functions = Math.GetMembers();
            MethodInfo mi;

            foreach (MemberInfo function in functions)
            {
                if (function.MemberType == MemberTypes.Method)
                {
                    mi = Math.GetMethod(function.Name);
                    if (mi.IsStatic && mi.IsPublic && mi.ReturnType == typeof(double))
                    {
                       Attribute[] atr = Attribute.GetCustomAttributes(mi);
                       if (atr.Length > 0)
                       {
                           if (atr[0] is Evalable) this.Functions.Add(function.Name.ToLower(), mi.GetParameters().Length);
                       }
                    }
                }
            }
        }

        public int this[string functionname]
        {
            get
            {
                if (this.Functions.ContainsKey(functionname)) return this.Functions[functionname];
                else return -1;
            }
        }

        public double InvokeFunction(string functionname, object[] param)
        {
            if (this.Functions.ContainsKey(functionname))
            {
                Type Math = Type.GetType("CalcSharp.MathFuncts");
                MethodInfo inf = Math.GetMethod(functionname);
                if (inf == null) throw new CSException("Function call error: " + functionname);
                return (double)inf.Invoke(null, param);
            }
            else throw new CSException("Function not supported for evaluation: "+functionname);
        }

        public string RegexFunctions
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                int c = 0;
                foreach (string key in this.Functions.Keys)
                {
                    sb.Append(key);
                    c++;
                    if (c < this.Functions.Keys.Count - 1) sb.Append("|");
                }
                return sb.ToString();
            }
        }

        public static double CallUserFunction(string p, double[] param)
        {
            StringBuilder command = new StringBuilder();
            command.Append(p);
            command.Append(" ");
            foreach (double d in param)
            {
                command.Append(d);
                command.Append(" ");
            }
            Tresult res = Program.loaded.RunOneCommand(command.ToString());
            return res.floatingpt;
        }
    }
}
